package xyj.sparrow.scheduler.server.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import xyj.sparrow.scheduler.server.service.impl.RegisterServiceImpl;
import xyj.sparrow.scheduler.service.ITaskLogService;
import xyj.sparrow.scheduler.util.ApplicationContextUtil;
import xyj.sparrow.scheduler.util.RpcServiceImplUtil;
import xyj.sparrow.common.netty.bean.BaseMsg;
import xyj.sparrow.common.netty.bean.Request;
import xyj.sparrow.common.netty.bean.Response;
import xyj.sparrow.common.netty.bean.Result;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @ClassName NettyServerHandler
 * @Description TODO
 * @Author Jim
 * @Date 2021/1/12 14:54
 * @Version 1.0.0
 **/
@EqualsAndHashCode(callSuper = true)
@Slf4j
@Data
public class NettyServerHandler extends SimpleChannelInboundHandler<BaseMsg> {
    int times;
    private ConcurrentHashMap<String, String> classMap = new ConcurrentHashMap<>();


    private RpcServiceImplUtil rpcServiceImplUtil;

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        //send register class
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, BaseMsg msg) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIP = insocket.getAddress().getHostAddress();
        log.info("服务端收到来自" + clientIP + "的消息：" + msg);
        if (msg instanceof Request) {
            Request request = (Request) msg;
            switch (request.getRequestType()) {
                case Request.RequestType.TRANSFER:
                    transfer(ctx, request);
                    break;
                case Request.RequestType.REGISTER:
                    register(ctx, request);
                    break;
                default:
                    break;
            }
        } else {
            log.info("{}", msg.toString());
            Response response = (Response) msg;
            if (response.getCode() == 1) {
                Result<String> result = (Result<String>) response.getObject();
                ApplicationContextUtil.getBean(ITaskLogService.class).logEnd(result);
            }
        }

        ctx.fireChannelRead(msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        try {
            super.exceptionCaught(ctx, cause);
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 注册 appid->taskid
     *
     * @param ctx
     * @param request
     * @author Jim
     * @since 2021/6/15 上午11:46
     **/

    private void register(ChannelHandlerContext ctx, Request request) {
        try {
            String className = RegisterServiceImpl.class.getName();
            Class<?> clz = Class.forName(className);
            Object object = clz.newInstance();

            Method method = clz.getMethod(request.getMethodName(), request.getParamTypes());
            Object[] params = request.getParams();
            params[params.length - 1] = ctx;
            Object invoke = method.invoke(object, params);
            send(ctx, invoke, request.getRequestId());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            sendError(ctx, request.getRequestId());
        }
    }

    private void transfer(ChannelHandlerContext ctx, Request request) {
        log.info("调用:" + ++times);
        try {
            String className = rpcServiceImplUtil.getRpcServiceImpl(request.getAliasName());
            if (classMap.containsKey(className)) className = classMap.get(className);
//            log.info(className);
            Class<?> clz = Class.forName(className);
            Object object = clz.newInstance();

            Method method = clz.getMethod(request.getMethodName(), request.getParamTypes());
            Object invoke = method.invoke(object, request.getParams());
            send(ctx, invoke, request.getRequestId());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            sendError(ctx, request.getRequestId());
        }

    }

    private void sendError(ChannelHandlerContext ctx, String requestId) {
        Response response = new Response();
        response.setRequestId(requestId);
        response.setCode(-1);
        response.setMsg("发生错误");
        response.setObject(null);
        ctx.channel().writeAndFlush(response);
    }


    private void send(ChannelHandlerContext ctx, Object invoke, String requestId) {
        Response response = new Response();
        response.setRequestId(requestId);
        response.setCode(1);
        response.setMsg("你好，执行成功");
        response.setObject(invoke);
        ctx.channel().writeAndFlush(response);
    }
}
